home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_Clock / Animator.m < prev    next >
Text File  |  1992-09-22  |  4KB  |  189 lines

  1.  
  2. /*
  3. *    Taken from the stop watch application in NextDeveloper .
  4. */
  5.  
  6. //  Animator.m
  7. //  Object for general timing, animation, and dynamics.
  8. //  Author: R. E. Crandall, Educational Technology Center
  9. //  10-Apr-88
  10. //  Revised by Bluce Blumberg for 0.8, 29-Sep-88
  11. //  Revised for 1.0 by Ali Ozer, 13-Jun-89
  12.  
  13.  
  14. /*
  15.  *  An 'Animator' controls the timing for your action method of choice.
  16.  *  The object may function as a general timer object; i.e.
  17.  *  graphics are neither expected nor required by the class.
  18.  *  When you create an Animator with +newChronon, you specify
  19.  *  the time interval between calls, the adaptation time constant (see below),
  20.  *  the target to which the method belongs, the action name, whether to 
  21.  *  automatically start up the timing upon creation, and an event mask (if you     
  22.  *  plan to break conditionally out of loops within the action method.
  23.  *
  24.  *  The Animator has adaptive means for adjusting to harsh operating
  25.  *  environments.  An adaptation constant d > 0. will invoke dynamical 
  26.  *  correction of entry times, on-the-fly, so that the desired chronon
  27.  *  will be realized in a real-time sense.
  28.  *
  29.  *  Functionality and applications are discussed in Report ETC-0008.
  30.  */
  31.  
  32. #import "Animator.h"
  33.  
  34. #import <appkit/Application.h>
  35. #import <sys/time.h>
  36. #import <objc/vectors.h>
  37.  
  38. @implementation Animator
  39.  
  40. void TimerFunc(teNum,now,self)
  41. DPSTimedEntry teNum;
  42. double now;
  43. id self;
  44. {
  45.   gettimeofday(&self->entrytime,NULL);
  46.   if (self->howOften > 0.) [self adapt];
  47.   [self->target perform:self->action with:self];
  48. }
  49.  
  50. + newChronon: (double) dt    /* The time increment desired. */
  51.     adaptation:(double)howoft  /* Adaptive time constant (0.deactivates).*/
  52.     target: (id) targ    /* Target to whom proc belongs. */
  53.     action: (SEL) act    /* The action. */
  54.     autoStart: (int) start    /* Automatic start of timed entry? */
  55.     eventMask: (int) eMask  /* Mask for optional check in "shouldBreak". */
  56. {
  57.   self = [super new];
  58.   ticking = NO;
  59.   desireddt = dt;
  60.   [self setIncrement: dt];
  61.   [self setAdaptation: howoft];
  62.   [self setTarget: targ];
  63.   [self setAction: act];
  64.   if(start) [self startEntry];
  65.   mask = eMask;
  66.   [self resetRealTime];
  67.   return self;
  68. }
  69.  
  70. - resetRealTime { 
  71. /* After this call, getDoubleRealTime is the real time that ensues. */
  72.     struct timeval realtime;
  73.  
  74.     gettimeofday(&realtime,NULL);
  75.     synctime = realtime.tv_sec + realtime.tv_usec/1000000.0;
  76.     passcounter = 0;
  77.     t0 = 0.0;
  78.     return self;
  79. }
  80.  
  81. - (double) getSyncTime {
  82.     return(synctime);
  83. }
  84.  
  85. - (double) getDoubleEntryTime {
  86. /* Returns real time since "resetrealTime". */
  87.     return(- synctime + entrytime.tv_sec + entrytime.tv_usec/1000000.0);
  88. }
  89.  
  90. - (double) getDoubleRealTime {
  91. /* Returns real time since "resetrealTime". */
  92.     struct timeval realtime;
  93.     struct timezone tzone;
  94.  
  95.     gettimeofday(&realtime,&tzone);
  96.     return(- synctime + realtime.tv_sec + realtime.tv_usec/1000000.0);
  97. }
  98.  
  99. - (double) getDouble {
  100.     return([self getDoubleRealTime]);
  101. }
  102.  
  103. - adapt {
  104. /* Adaptive time-step algorithm. */
  105.   double t;
  106.   if(!ticking) return self;
  107.   ++passcounter;
  108.   t = [self getDoubleEntryTime];
  109.   if(t - t0 >= howOften) {      
  110.       adapteddt *= desireddt*passcounter/(t - t0);
  111.     [self setIncrement: adapteddt];
  112.     [self startEntry];
  113.     passcounter = 0;
  114.     t0 = t;
  115.   }
  116.   return self;
  117. }
  118.   
  119. - setBreakMask : (int) eventMask {
  120.   mask = eventMask;
  121.   return self;
  122. }
  123.  
  124. - (int) getBreakMask {
  125.   return(mask);
  126. }
  127.  
  128. - (int) isTicking {
  129.   return(ticking);
  130. }
  131.    
  132. - (int) shouldBreak  {
  133. /* Call this to see if you want to exit a loop in your action method. */
  134.    int   found;
  135.    NXEvent *e, event;
  136.    e = [NXApp peekNextEvent:mask into:&event 
  137.           waitFor:0.0 threshold:NX_BASETHRESHOLD];
  138.    return(e ? 1: 0);
  139. }
  140.  
  141. - setIncrement: (double) dt {
  142.   adapteddt = dt;
  143.   interval = dt;
  144.   return self;
  145. }
  146.  
  147. - (double) getIncrement {
  148.   return(adapteddt);
  149. }
  150.  
  151. - setAdaptation: (double) oft {
  152.   howOften = oft;
  153.   return self;
  154. }
  155.  
  156. - setTarget: (id) targ {
  157.   target = targ;
  158. }
  159.  
  160. - setAction:(SEL) aSelector
  161. {
  162.     action = aSelector;
  163.  
  164.     return self;
  165. }
  166.  
  167. - startEntry
  168.   [self stopEntry];
  169.   teNum = DPSAddTimedEntry(interval,&TimerFunc,self,NX_BASETHRESHOLD);
  170.   ticking = YES;
  171.   return self;
  172. }
  173.  
  174. - stopEntry
  175. {
  176.   if (ticking) DPSRemoveTimedEntry(teNum);
  177.   ticking = NO;
  178.   return self;
  179. }
  180.  
  181. - free
  182. {
  183.   if (ticking) DPSRemoveTimedEntry(teNum);
  184.   return [super free];
  185. }
  186.  
  187. @end    
  188.